read <src>
Added in 6.4.0.
contract.read is a typed, ergonomic namespace that exposes a contract's
view / pure
(and legacy constant) functions. A read is executed through triggerConstantContract,
does not modify the chain, costs nothing, and resolves directly to the decoded
result.
State-changing functions live in the write namespace instead. When the
ABI is declared as const, function names and argument types are checked at compile
time. This is the recommended alternative to the flat .call()
surface.
Every namespace method is async. All validation (argument count, call value, …)
surfaces as a promise rejection, never a synchronous throw — always await the call.
Usage
// Signature (each method on the namespace)
contract.read.<fn>(args: unknown[], options?: ReadOptions): Promise<Decoded>
contract.read.<fn>(options?: ReadOptions): Promise<Decoded> // for a no-argument method
type ReadOptions = { from?: string; value?: number | bigint };
const abi = [...] as const;
const contract = tronWeb.contract(abi, 'contractAddress');
// resolves to the decoded return value
const result = await contract.read.methodName([arg0, arg1, ...], options);
The first positional argument is the array of method arguments. For a method that takes no arguments you may pass nothing, or pass the options object directly:
await contract.read.totalSupply(); // no args
await contract.read.totalSupply(options); // no args, with options
await contract.read.balanceOf([owner]); // one arg
Parameters
| Parameter | Description | Type |
|---|---|---|
| args | Array of the method's arguments, in ABI order. Addresses may be base58 or hex. Omit for a no-arg method. | unknown[] |
| options | Optional. Call options (see below). | object |
read options
| Option | Description | Type |
|---|---|---|
| from | The caller (issuer) address for the constant call (base58 or hex). Falls back to the instance's default address. | string |
| value | TRX (in sun) attached to the call (callValue). | number | bigint |
A caller address is required: pass from, or set a default address on the TronWeb instance — if neither is set the call rejects (it is not issued from a zero address). To issue/sign as a specific account, use the write namespace's account (private key) option; account is write-only and is not accepted by read.
Returns
The decoded output. A single output is collapsed to the bare value (e.g. a uint256
resolves to a bigint); multiple outputs resolve to an array. A function that declares
no outputs resolves to undefined; a function that declares outputs but returns no
data rejects with Failed to execute.
Selector form (overloads)
Each function is additionally exposed under its full selector, e.g.
contract.read['balanceOf(address)']. The selector form pins that exact overload, so
same-arity overloads can be addressed unambiguously:
const balance = await contract.read['balanceOf(address)'](['TXXX...']);
When two overloads share the same arity, the bare name cannot pick one and the call
rejects with Ambiguous overloaded function "<name>" ... — use the selector key to
disambiguate.
The selector key is a function's canonical signature — its name followed by the
parenthesized input types in canonical form (bare uint / int widen to
uint256 / int256, tuples flatten to (type,…); trcToken is kept as-is per the TVM
convention). Rather than hand-writing it, derive it from an ABI fragment with
tronWeb.utils.abi.buildFunctionSelector — it returns this exact string, the same value
the namespace registers internally:
const fragment = abi.find((f) => f.name === 'balanceOf');
const key = tronWeb.utils.abi.buildFunctionSelector(fragment); // 'balanceOf(address)'
await contract.read[key](['TXXX...']);
Namespaces enumerate each method under both its bare name and its selector, so
Object.keys(contract.read) returns two entries per function:
Object.keys(contract.read); // ['balanceOf', 'balanceOf(address)']
Functions named read
If the ABI literally defines a function called read, it stays callable through the
legacy flat surface, and the namespace is served from the same object — so both work:
await contract.read().call(); // legacy flat call → triggerSmartContract
await contract.read.read(); // namespace entry → triggerConstantContract
Validation & errors
All of the following reject the returned promise:
| Condition | Error message |
|---|---|
| Wrong number of arguments | Contract function "<name>" expects <n> argument(s) but received <m>. |
| Ambiguous same-arity overload (bare name) | Ambiguous overloaded function "<name>" for the given arguments; pass the full signature ... |
Calling read on a state-changing function | Function "<name>" is not read-only. |
from is not a valid address | The "from" option must be a valid address. |
No caller address (from unset and no default) | A caller address is required. Set the "from" option or a default address on the TronWeb instance. |
| A function with declared outputs returns no data | Failed to execute |
Invalid value | call value cannot be negative / call value must be an integer / call value exceeds safe integer range / call value must be a number or bigint |
Example
const abi = [
{
type: 'function',
name: 'balanceOf',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ name: 'balance', type: 'uint256' }],
},
] as const;
async function demo() {
const contract = tronWeb.contract(abi, 'TContractAddress...');
// only `view` / `pure` functions appear here
const balance = await contract.read.balanceOf(['TOwnerAddress...']);
console.log(balance);
42n
// override the caller (issuer) address explicitly, plus a call value (in sun)
await contract.read.balanceOf(['TOwnerAddress...'], { from: 'TCallerAddress...', value: 3n });
}
demo();